/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Charts module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmydisplaydevice.h"
#include <QVector>
#include <QPointF>
#include <QDebug>
#include <QBarSet>
#include <QBarSeries>

// AudioProcessorThread构造函数
// 参数: parent - 父对象
// 功能: 初始化音频处理线程
AudioProcessorThread::AudioProcessorThread(QObject* parent)
    : QThread(parent)
{
}

// AudioProcessorThread析构函数
// 功能: 停止线程并等待其结束
AudioProcessorThread::~AudioProcessorThread()
{
    stop();
    wait();
}

// 设置音频处理参数
// 参数:
//   data - 音频数据指针
//   size - 数据大小
//   series - 折线图系列对象
//   barSeries - 条形图系列对象
//   barSet - 条形数据集对象
//   range - 数据范围
//   mode - 音频模式
//   chartType - 图表类型
// 功能: 设置线程处理的参数并唤醒线程进行处理
void AudioProcessorThread::setParameters(const char* data, qint64 size, QLineSeries* series,
                                     QBarSeries* barSeries, QBarSet* barSet,
                                     qint64 range, int mode, int chartType)
{
    QMutexLocker locker(&m_mutex);
    m_data = data;
    m_size = size;
    m_series = series;
    m_barSeries = barSeries;
    m_barSet = barSet;
    m_range = range;
    m_mode = mode;
    m_chartType = chartType;
    m_condition.wakeOne();
}

// 停止线程
// 功能: 请求线程停止执行并唤醒线程以便退出
void AudioProcessorThread::stop()
{
    QMutexLocker locker(&m_mutex);
    m_stopRequested = true;
    m_condition.wakeOne(); // 唤醒线程以便退出
}

// 线程运行函数
// 功能: 在线程中处理音频数据并更新图表
void AudioProcessorThread::run()
{
    while (!m_stopRequested) {
        QVector<QPointF> points;
        char* localData = nullptr;
        qint64 localSize = 0;
        QLineSeries* localSeries = nullptr;
        qint64 localRange = 0;
        int localMode = 0;
        int localChartType = 0;
        QBarSet* localBarSet = nullptr;
        QBarSeries* localBarSeries = nullptr;

        // 等待数据并获取处理参数
        {
            QMutexLocker locker(&m_mutex);
            if (!m_data || m_size <= 0) {
                m_condition.wait(&m_mutex);
                if (m_stopRequested) break;
                if (!m_data || m_size <= 0) continue;
            }
            
            // 复制参数
            localData = const_cast<char*>(m_data);
            localSize = m_size;
            localSeries = m_series;
            localRange = m_range;
            localMode = m_mode;
            localChartType = m_chartType;
            localBarSet = m_barSet;
            localBarSeries = m_barSeries;
            
            // 重置参数，等待新的数据
            m_data = nullptr;
            m_size = 0;
        }

        // 同时处理两种图表类型的数据
        QVector<QPointF> linePoints;
        
        // 处理折线图数据
        if (localMode == QmyDisplayDevice::PCM) {
            linePoints = processPCMData(localData, localSize, localSeries, localRange);
        } else {
            linePoints = processATUIMData(localData, localSize, localSeries, localRange);
        }
        
        // 发送折线图处理结果
        emit processingFinished(linePoints);
        
        // 处理条形图数据
            if (localBarSet) {
                // 清空现有的条形数据
                int count = localBarSet->count();
                if (count > 0) {
                    localBarSet->remove(0, count);
                }
                
                // 固定显示10个矩形
                const int BAR_COUNT = 10;
                
                // 计算每个矩形的数据范围
                qint64 samplesPerBar = localSize / BAR_COUNT;
                if (samplesPerBar < 1) samplesPerBar = 1;
                
                // 根据音频模式处理数据并填充条形图
                if (localMode == QmyDisplayDevice::PCM) {
                    // PCM模式：将数据转换为10个条形
                    for (int barIndex = 0; barIndex < BAR_COUNT; barIndex++) {
                        qreal avgValue = 0;
                        qint64 sampleCount = 0;
                        
                        // 计算该条形范围内的平均值
                        for (qint64 i = barIndex * samplesPerBar; i < (barIndex + 1) * samplesPerBar && i < localSize; i += 2) {
                            if (i >= localSize) break;
                            avgValue += static_cast<uchar>(localData[i]);
                            sampleCount++;
                        }
                        
                        // 添加平均值作为条形高度，如果没有采样点则设为0
                        if (sampleCount > 0) {
                            avgValue = qMin(avgValue / sampleCount, 255.0);
                        } else {
                            avgValue = 0;
                        }
                        localBarSet->append(avgValue);
                    }
                } else {
                    // ATUIM模式：对数据进行转换后显示为10个条形
                    for (int barIndex = 0; barIndex < BAR_COUNT; barIndex++) {
                        qreal avgValue = 0;
                        qint64 sampleCount = 0;
                        
                        // 计算该条形范围内的平均值
                        for (qint64 i = barIndex * samplesPerBar; i < (barIndex + 1) * samplesPerBar && i + 1 < localSize; i += 2) {
                            if (i + 1 >= localSize) break;
                            short sample = *reinterpret_cast<const short*>(localData + i);
                            // 将有符号值转换为0-255范围
                            avgValue += static_cast<uchar>((sample + 32768) / 256);
                            sampleCount++;
                        }
                        
                        // 添加平均值作为条形高度，如果没有采样点则设为0
                        if (sampleCount > 0) {
                            avgValue = qMin(avgValue / sampleCount, 255.0);
                        } else {
                            avgValue = 0;
                        }
                        localBarSet->append(avgValue);
                    }
                }
            }
    }
}

// 处理PCM音频数据
// 参数:
//   data - 音频数据指针
//   maxSize - 最大数据大小
//   series - 折线图系列对象
//   range - 数据范围
// 返回值: 处理后的点集合
// 功能: 处理PCM格式的音频数据并转换为图表点集
QVector<QPointF> AudioProcessorThread::processPCMData(const char* data, qint64 maxSize, 
                                                     QLineSeries* series, qint64 range)
{
    QVector<QPointF> oldPoints = series->pointsVector();
    QVector<QPointF> points;

    if (oldPoints.count() < range) {
        points = oldPoints;
    } else {
        points.reserve(range);
        for (int i = maxSize; i < oldPoints.count(); ++i) {
            points.append(QPointF(i - maxSize, oldPoints.at(i).y()));
        }
    }

    qint64 size = points.count();
    points.reserve(size + maxSize);
    for (int k = 0; k < maxSize; ++k) {
        // PCM模式：直接使用数据值
        points.append(QPointF(k + size, static_cast<quint8>(data[k])));
    }

    return points;
}

// 处理ATUIM音频数据
// 参数:
//   data - 音频数据指针
//   maxSize - 最大数据大小
//   series - 折线图系列对象
//   range - 数据范围
// 返回值: 处理后的点集合
// 功能: 处理ATUIM格式的音频数据并转换为图表点集
QVector<QPointF> AudioProcessorThread::processATUIMData(const char* data, qint64 maxSize, 
                                                       QLineSeries* series, qint64 range)
{
    QVector<QPointF> oldPoints = series->pointsVector();
    QVector<QPointF> points;

    if (oldPoints.count() < range) {
        points = oldPoints;
    } else {
        points.reserve(range);
        for (int i = maxSize; i < oldPoints.count(); ++i) {
            points.append(QPointF(i - maxSize, oldPoints.at(i).y()));
        }
    }

    qint64 size = points.count();
    points.reserve(size + maxSize);
    
    for (int k = 0; k < maxSize; ++k) {
        // ATUIM模式：可以添加特定的处理逻辑
        quint8 value = static_cast<quint8>(data[k]);
        // 例如：增强某些频率范围或应用特定的处理算法
        value = (value > 128) ? (value * 1.2) : (value * 0.8);
        // 确保值在有效范围内
        if (value > 255) value = 255;
        
        points.append(QPointF(k + size, value));
    }

    return points;
}

// QmyDisplayDevice构造函数
// 参数:
//   series - 折线图系列对象
//   barSeries - 条形图系列对象
//   barSet - 条形数据集对象
//   pointCount - 显示的点数量
//   parent - 父对象
// 功能: 初始化音频显示设备，创建处理线程和定时器
QmyDisplayDevice::QmyDisplayDevice(QLineSeries* series, QBarSeries* barSeries, QBarSet* barSet,
                                 qint64 pointCount, QObject* parent)
    : QIODevice(parent), m_series(series), m_barSeries(barSeries), m_barSet(barSet), m_range(pointCount)
{
    m_delayTimer = new QTimer(this);
    m_delayTimer->setInterval(30); // 30ms延时
    m_delayTimer->setSingleShot(true);
    connect(m_delayTimer, &QTimer::timeout, this, &QmyDisplayDevice::handleDelayedUpdate);
    
    // 创建并启动音频处理线程
    m_processorThread = new AudioProcessorThread(this);
    connect(m_processorThread, &AudioProcessorThread::processingFinished, 
            this, &QmyDisplayDevice::handleProcessingFinished);
    m_processorThread->start();
}

// QmyDisplayDevice析构函数
// 功能: 停止定时器和处理线程，释放资源
QmyDisplayDevice::~QmyDisplayDevice()
{
    m_delayTimer->stop();
    
    // 停止处理线程
    if (m_processorThread) {
        m_processorThread->stop();
        m_processorThread->wait();
        delete m_processorThread;
    }
}

// 读取数据函数（未实现）
// 参数:
//   data - 数据缓冲区
//   maxSize - 最大读取大小
// 返回值: 总是返回-1，表示不支持读取
// 功能: 实现QIODevice接口，但本设备只支持写入
qint64 QmyDisplayDevice::readData(char* data, qint64 maxSize)
{
    Q_UNUSED(data);
    Q_UNUSED(maxSize);
    return -1;
}

// 处理延时更新
// 功能: 延时后发射数据块大小更新信号
void QmyDisplayDevice::handleDelayedUpdate()
{
    emit updateBlockSize(m_lastBlockSize);
}

// 处理数据处理完成事件
// 参数: points - 处理后的点集合
// 功能: 在主线程中更新折线图数据
void QmyDisplayDevice::handleProcessingFinished(const QVector<QPointF>& points)
{
    // 在主线程中更新图表
    m_series->replace(points);
}

// 设置音频模式
// 参数: mode - 音频模式枚举值
// 功能: 设置设备的音频处理模式
void QmyDisplayDevice::setAudioMode(AudioMode mode)
{
    m_mode = mode;
}

// 获取当前音频模式
// 返回值: 当前的音频模式
// 功能: 返回设备当前的音频处理模式
QmyDisplayDevice::AudioMode QmyDisplayDevice::audioMode() const
{
    return m_mode;
}

// 设置图表类型
// 参数: type - 图表类型枚举值
// 功能: 设置显示的图表类型并清空当前数据
void QmyDisplayDevice::setChartType(ChartType type)
{
    m_chartType = type;
    
    // 清空当前显示的数据
    if (type == LineChart && m_series) {
        m_series->clear();
    } else if (type == RectChart && m_barSet) {
        // QBarSet没有clear方法，我们可以移除所有元素
        int count = m_barSet->count();
        if (count > 0) {
            m_barSet->remove(0, count);
        }
    }
}

// 获取当前图表类型
// 返回值: 当前的图表类型
// 功能: 返回设备当前的图表显示类型
QmyDisplayDevice::ChartType QmyDisplayDevice::chartType() const
{
    return m_chartType;
}



// 写入数据函数
// 参数:
//   data - 音频数据指针
//   maxSize - 数据大小
// 返回值: 写入的数据大小
// 功能: 处理写入的音频数据，启动处理线程并发射信号
qint64 QmyDisplayDevice::writeData(const char* data, qint64 maxSize)
{
    // 保存当前数据块大小用于延时显示
    m_lastBlockSize = maxSize;

    // 发射音频数据信号，用于录制
    emit audioDataAvailable(QByteArray(data, maxSize));

    // 复制数据到本地缓冲区，避免在处理过程中被覆盖
    {   
        QMutexLocker locker(&m_dataMutex);
        m_currentData = QByteArray(data, maxSize);
    }
    
    // 在线程中处理数据，避免阻塞主线程
    if (m_processorThread->isRunning()) {
        m_processorThread->setParameters(m_currentData.constData(), maxSize, m_series, 
                                       m_barSeries, m_barSet, m_range, m_mode, 0); // 不再需要chartType参数
    }

    // 启动30ms延时定时器
    m_delayTimer->start();

    return maxSize;
}
